﻿using System;
using System.Reflection;
using System.Windows.Forms;
using Scrobbler.UI.WF.Interfaces;
using Scrobbler.UI.WF.Presenters;

namespace Scrobbler.UI.WF.Windows
{
    public partial class MainWindow : Form, IMainWindow
    {
        private readonly MainWindowPresenter _presenter;
        private readonly string _appName = "BBC Radio Scrobbler";
        private ToolStripItem StatusTarget { get { return statusBarText; } }
        private Label SongInfoTarget { get { return songInfo; } }
        private NotifyIcon _trayIcon;
        private ContextMenu _trayMenu;
        private string _currentSong = string.Empty;

        private delegate void SetTextCallback(string text);

        public MainWindow()
        {
            InitializeComponent();

            _presenter = new MainWindowPresenter(this);
            _presenter.InitConfig();

            InitUi();
            InitAdditionalEvents();
        }

        private void InitTrayMenu()
        {
            _trayMenu = new ContextMenu();

            var openItem = new MenuItem { Text = "Open" };
            openItem.Click += (o, args) => ToTray(false);

            var closeItem = new MenuItem { Text = "Close" };
            closeItem.Click += (o, args) => Application.Exit();

            _trayMenu.MenuItems.Add(openItem);
            _trayMenu.MenuItems.Add(closeItem);
        }

        private void InitUi()
        {
            var dataSource = _presenter.GetRadiosDataSource();
            radiosList.DataSource = new BindingSource(dataSource, null);
            radiosList.DisplayMember = "Value";
            radiosList.ValueMember = "Key";
            radiosList.SelectedIndex = 0;

            Text = string.Format("{0} {1} (beta)", _appName, Assembly.GetExecutingAssembly().GetName().Version);
        }

        private void InitAdditionalEvents()
        {
            SizeChanged += OnSizeChanged;
        }

        private void OnSizeChanged(object sender, EventArgs eventArgs)
        {
            var trayIconInactive = _trayIcon == null || !_trayIcon.Visible;
            if (WindowState == FormWindowState.Minimized && trayIconInactive)
            {
                ToTray(true);
            }
        }

        private void InitTrayIcon()
        {
            if (_trayIcon != null) return; // Lazy initialization

            InitTrayMenu();

            var resources = new System.ComponentModel.ComponentResourceManager(typeof(MainWindow));

            _trayIcon = new NotifyIcon
                            {
                                Text = _currentSong,
                                Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))),
                                ContextMenu = _trayMenu,
                                Visible = true,
                            };

            _trayIcon.DoubleClick += (o, args) => RestoreFromTray();
            _trayIcon.MouseDoubleClick += (o, args) => RestoreFromTray();
        }

        public void UpdateUiOnScrobbling()
        {
            UpdateUi(scrobbleButtonEnabled: false,
                    stopScrobblingButtonEnabled: true,
                    radioListEnabled: false);
        }

        public void UpdateUiWaitingForFinishingAction()
        {
            UpdateUi(scrobbleButtonEnabled: false,
                stopScrobblingButtonEnabled: false,
                radioListEnabled: false,
                songInfoReset: true,
                statusInfoReset: true);
        }

        public void UpdateUiOnNotScrobbling()
        {
            UpdateUi(scrobbleButtonEnabled: true,
                stopScrobblingButtonEnabled: false,
                radioListEnabled: true,
                songInfoReset: true,
                statusInfoReset: true);
        }

        public IStreamSource GetRadio()
        {
            return (IStreamSource)Activator.CreateInstance((Type)radiosList.SelectedValue);
        }

        public void SetStatus(string text)
        {
            if (SongInfoTarget.InvokeRequired)
            {
                var callback = new SetTextCallback(SetStatus);
                Invoke(callback, new object[] { text });
            }
            else
            {
                StatusTarget.Text = text;
            }
        }

        public void UpdateSongInfo(string text)
        {
            _currentSong = text;
            UpdateMainWindowSongInfo(text);
            UpdateTrayIconSongInfo(text);
        }

        private void UpdateTrayIconSongInfo(string text)
        {
            if (_trayIcon == null) return;
            _trayIcon.Text = text;
        }

        private void UpdateMainWindowSongInfo(string text)
        {
            if (SongInfoTarget.InvokeRequired)
            {
                var callback = new SetTextCallback(UpdateSongInfo);
                Invoke(callback, new object[] {text});
            }
            else
            {
                SongInfoTarget.Text = text;
            }
        }

        private void scrobbleButton_Click(object sender, EventArgs e)
        {
            _presenter.Scrobble();
        }

        private void stopScrobblingButton_Click(object sender, EventArgs e)
        {
            _presenter.StopScrobbling();
        }

        private void UpdateUi(bool scrobbleButtonEnabled = true,
            bool stopScrobblingButtonEnabled = true,
            bool radioListEnabled = true,
            bool songInfoReset = false,
            bool statusInfoReset = false)
        {
            scrobbleButton.Enabled = scrobbleButtonEnabled;
            stopScrobblingButton.Enabled = stopScrobblingButtonEnabled;
            radiosList.Enabled = radioListEnabled;
            if (songInfoReset) songInfo.Text = string.Empty;
            if (statusInfoReset) statusBarText.Text = string.Empty;
        }

        private void configurationToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var cfgWindows = new ConfigurationWindow(_presenter.Conf.Configuration);
            cfgWindows.ShowDialog(this);
        }

        private void openInBrowserButton_Click(object sender, EventArgs e)
        {
            _presenter.OpenInBrowser();
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var aboutBox = new AboutBox();
            aboutBox.ShowDialog(this);
        }

        private void visitWebsiteToolStripMenuItem_Click(object sender, EventArgs e)
        {
            _presenter.GoToWebsite();
        }

        /// <summary>
        /// Minimize application to tray
        /// </summary>
        /// <param name="toTray">Minimize to tray. Otherwise, restore from tray.</param>
        private void ToTray(bool toTray = true)
        {
            Visible = !toTray;
            ShowInTaskbar = !toTray;
            if (toTray) InitTrayIcon();
            _trayIcon.Visible = toTray;
            if (!toTray) WindowState = FormWindowState.Normal;
        }

        private void RestoreFromTray()
        {
            ToTray(false);
        }
    }
}
